home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / dev / debug / Sashimi.lha / source / sashimi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-12  |  22.6 KB  |  979 lines

  1. /*
  2.  * $Id: sashimi.c 1.6 1998/09/11 22:03:36 olsen Exp olsen $
  3.  *
  4.  * Sashimi -- intercepts raw serial debugging output on your own machine
  5.  *
  6.  * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  7.  * Public Domain
  8.  *
  9.  * :ts=4
  10.  */
  11.  
  12. #include <exec/memory.h>
  13.  
  14. #include <devices/timer.h>
  15.  
  16. #include <dos/dosextens.h>
  17. #include <dos/rdargs.h>
  18.  
  19. #include <clib/exec_protos.h>
  20. #include <clib/dos_protos.h>
  21.  
  22. #include <pragmas/exec_sysbase_pragmas.h>
  23. #include <pragmas/dos_pragmas.h>
  24.  
  25. #include <string.h>
  26. #include <stdio.h>
  27.  
  28. /****************************************************************************/
  29.  
  30. STRPTR Version = "$VER: Sashimi 1.4 (11.9.98)\r\n";
  31.  
  32. /****************************************************************************/
  33.  
  34. #define OK        (0)
  35. #define NOT        !
  36. #define BUSY    NULL
  37.  
  38. /****************************************************************************/
  39.  
  40. #define MILLION 1000000
  41.  
  42. /****************************************************************************/
  43.  
  44. extern struct Library * SysBase;
  45. extern struct Library * DOSBase;
  46.  
  47. /****************************************************************************/
  48.  
  49. typedef LONG    SWITCH;
  50. typedef LONG *    NUMBER;
  51. typedef STRPTR    KEY;
  52.  
  53. struct
  54. {
  55.     /* Startup options */
  56.     SWITCH    On;            /* Ignored */
  57.     NUMBER    BufferK;    /* Buffer size, to the power of two */
  58.     NUMBER    BufferSize;    /* Buffer size in bytes */
  59.     SWITCH    NoPrompt;    /* Do not show the initial prompt message */
  60.     SWITCH    Quiet;        /* Do not produce any output at all */
  61.     SWITCH    AskExit;    /* Ask whether to exit the program */
  62.     SWITCH    AskSave;    /* Ask for a file to save the buffer to when exiting */
  63.     SWITCH    TimerOn;    /* Check the ring buffer every 1/10 of a second */
  64.     SWITCH    Console;    /* Open a console window for I/O */
  65.     KEY        Window;        /* Console window specifier */
  66.  
  67.     /* Runtime options */
  68.     SWITCH    Off;        /* Turn Sashimi off */
  69.     SWITCH    Save;        /* Save the ring buffer contents */
  70.     KEY        SaveAs;        /* Save the ring buffer contents under a specific name */
  71.     SWITCH    Empty;        /* Empty the ring buffer */
  72. } ShellArguments;
  73.  
  74. const STRPTR ShellTemplate = "ON/S,BUFK/N,BUFFERSIZE/N,NOPROMPT/S,QUIET/S,ASKEXIT/S,"
  75.                              "ASKSAVE/S,TIMERON/S,CONSOLE/S,WINDOW/K,"
  76.                              "OFF/S,SAVE/S,SAVEAS/K,EMPTY/S";
  77.  
  78. /****************************************************************************/
  79.  
  80. struct SashimiResource
  81. {
  82.     struct Library    sr_Library;            /* Global link */
  83.  
  84.     struct Task *    sr_Owner;            /* Current owner of the patches */
  85.     LONG            sr_OwnerSigBit;
  86.     ULONG            sr_OwnerSigMask;    /* Signal mask to send when a new line is in the buffer. */
  87.  
  88.     UBYTE *            sr_FIFO;            /* The message buffer */
  89.     ULONG            sr_FIFOTotalSize;    /* Number of bytes allocated for the buffer */
  90.     ULONG            sr_FIFOReadIndex;    /* Read index counter */
  91.     ULONG            sr_FIFOWriteIndex;    /* Write index counter */
  92.     ULONG            sr_FIFOBytesStored;    /* Number of bytes in the FIFO */
  93.     BOOL            sr_FIFOOverrun;        /* TRUE if the write index counter has
  94.                                          * overrun the read index counter.
  95.                                          */
  96.     BOOL            sr_FIFOWrapped;        /* TRUE if the write index counter has
  97.                                          * wrapped around the ring buffer.
  98.                                          */
  99. };
  100.  
  101. struct SashimiResource * SashimiResource;
  102. const STRPTR SashimiResourceName = "sashimi.resource";
  103.  
  104. /****************************************************************************/
  105.  
  106. extern LONG __far LVORawIOInit;
  107. extern LONG __far LVORawMayGetChar;
  108. extern LONG __far LVORawPutChar;
  109.  
  110. /****************************************************************************/
  111.  
  112. APTR OldRawIOInit;
  113. APTR OldRawMayGetChar;
  114. APTR OldRawPutChar;
  115.  
  116. /****************************************************************************/
  117.  
  118. VOID __saveds __asm
  119. NewRawIOInit(VOID)
  120. {
  121. }
  122.  
  123. LONG __saveds __asm
  124. NewRawMayGetChar(VOID)
  125. {
  126.     return('y');
  127. }
  128.  
  129. /****************************************************************************/
  130.  
  131. extern VOID __asm SafeRawPutChar(register __d0 UBYTE c);
  132.  
  133. VOID __saveds __asm
  134. NewRawPutChar(register __d0 UBYTE c)
  135. {
  136.     /* Do not store NUL bytes. */
  137.     if(c != '\0')
  138.     {
  139.         STATIC ULONG Position = 0;
  140.  
  141.         /* Filter out extra <cr> characters. */
  142.         if(c != '\r' || Position > 0)
  143.         {
  144.             struct SashimiResource * sr = SashimiResource;
  145.  
  146.             /* Store another byte in the buffer */
  147.             sr->sr_FIFO[sr->sr_FIFOWriteIndex] = c;
  148.             sr->sr_FIFOWriteIndex = (sr->sr_FIFOWriteIndex + 1) % sr->sr_FIFOTotalSize;
  149.  
  150.             /* Check if the ring buffer was overrun */
  151.             sr->sr_FIFOBytesStored++;
  152.             if(sr->sr_FIFOBytesStored >= sr->sr_FIFOTotalSize)
  153.             {
  154.                 sr->sr_FIFOOverrun = TRUE;
  155.  
  156.                 /* Move the read index to the same position as
  157.                  * the write index.
  158.                  */
  159.                 sr->sr_FIFOReadIndex = sr->sr_FIFOWriteIndex;
  160.             }
  161.  
  162.             /* If the buffer wraps around, remember it. */
  163.             if(sr->sr_FIFOWriteIndex == 0)
  164.                 sr->sr_FIFOWrapped = TRUE;
  165.  
  166.             /* Notify Sashimi every time there is an end of line
  167.              * character in the stream.
  168.              */
  169.             if(c == '\n' || c == '\r')
  170.                 Signal(sr->sr_Owner,sr->sr_OwnerSigMask);
  171.         }
  172.  
  173.         if(c == '\r' || c == '\n')
  174.             Position = 0;
  175.         else
  176.             Position++;
  177.     }
  178. }
  179.  
  180. /****************************************************************************/
  181.  
  182. VOID
  183. RemovePatches(VOID)
  184. {
  185.     APTR res;
  186.  
  187.     /* We disable the interrupts because the raw I/O routines can
  188.      * be called from within interrupt code.
  189.      */
  190.     Disable();
  191.  
  192.     /* For every patch planted, remove it and check whether the code
  193.      * had been patched before. If it has, restore the patch. Note that
  194.      * this is not bullet proof :(
  195.      */
  196.     res = SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())OldRawIOInit);
  197.     if(res != (APTR)NewRawIOInit)
  198.         SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())res);
  199.  
  200.     res = SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())OldRawMayGetChar);
  201.     if(res != (APTR)NewRawMayGetChar)
  202.         SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())res);
  203.  
  204.     res = SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())OldRawPutChar);
  205.     if(res != (APTR)SafeRawPutChar)
  206.         SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())res);
  207.  
  208.     Enable();
  209. }
  210.  
  211. VOID
  212. InstallPatches(VOID)
  213. {
  214.     /* We disable the interrupts because the raw I/O routines can
  215.      * be called from within interrupt code.
  216.      */
  217.     Disable();
  218.  
  219.     OldRawIOInit        = SetFunction(SysBase,(LONG)&LVORawIOInit,        (ULONG (*)())NewRawIOInit);
  220.     OldRawMayGetChar    = SetFunction(SysBase,(LONG)&LVORawMayGetChar,    (ULONG (*)())NewRawMayGetChar);
  221.     OldRawPutChar        = SetFunction(SysBase,(LONG)&LVORawPutChar,        (ULONG (*)())SafeRawPutChar);
  222.  
  223.     Enable();
  224. }
  225.  
  226. /****************************************************************************/
  227.  
  228. VOID
  229. FreeSashimiResource(struct SashimiResource * resource)
  230. {
  231.     if(resource != NULL)
  232.     {
  233.         FreeSignal(resource->sr_OwnerSigBit);
  234.  
  235.         FreeVec(resource->sr_FIFO);
  236.         FreeVec(resource);
  237.     }
  238. }
  239.  
  240. LONG
  241. RemoveSashimiResource(struct SashimiResource * resource)
  242. {
  243.     LONG error = OK;
  244.  
  245.     if(resource != NULL)
  246.     {
  247.         Forbid();
  248.  
  249.         /* Allow the resource to be removed only if
  250.          * there are no customers using it.
  251.          */
  252.         if(resource->sr_Library.lib_OpenCnt == 0)
  253.         {
  254.             RemResource(resource);
  255.         }
  256.         else
  257.         {
  258.             error = ERROR_OBJECT_IN_USE;
  259.         }
  260.  
  261.         Permit();
  262.     }
  263.  
  264.     return(error);
  265. }
  266.  
  267. LONG
  268. AddSashimiResource(ULONG bufferSize,struct SashimiResource ** resourcePtr)
  269. {
  270.     struct SashimiResource * resource;
  271.     LONG error = OK;
  272.  
  273.     resource = AllocVec(sizeof(*resource),MEMF_ANY|MEMF_CLEAR|MEMF_PUBLIC);
  274.     if(resource != NULL)
  275.     {
  276.         resource->sr_Library.lib_Node.ln_Name    = (char *)SashimiResourceName;
  277.         resource->sr_Library.lib_Node.ln_Type    = NT_RESOURCE;
  278.         resource->sr_Owner                        = FindTask(NULL);
  279.         resource->sr_FIFOTotalSize                = bufferSize;
  280.  
  281.         resource->sr_OwnerSigBit = AllocSignal(-1);
  282.         if(resource->sr_OwnerSigBit != -1)
  283.         {
  284.             resource->sr_OwnerSigMask = (1UL << resource->sr_OwnerSigBit);
  285.  
  286.             resource->sr_FIFO = AllocVec(resource->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
  287.             if(resource->sr_FIFO != NULL)
  288.             {
  289.                 Forbid();
  290.  
  291.                 /* Do not add the resource if it has already been installed. */
  292.                 if(OpenResource((STRPTR)SashimiResourceName) == NULL)
  293.                 {
  294.                     AddResource(resource);
  295.                 }
  296.                 else
  297.                 {
  298.                     error = ERROR_OBJECT_EXISTS;
  299.                 }
  300.  
  301.                 Permit();
  302.             }
  303.             else
  304.             {
  305.                 error = ERROR_NO_FREE_STORE;
  306.             }
  307.         }
  308.         else
  309.         {
  310.             error = ERROR_NO_FREE_STORE;
  311.         }
  312.     }
  313.     else
  314.     {
  315.         error = ERROR_NO_FREE_STORE;
  316.     }
  317.  
  318.     if(error != OK)
  319.     {
  320.         FreeSashimiResource(resource);
  321.         resource = NULL;
  322.     }
  323.  
  324.     *resourcePtr = resource;
  325.  
  326.     return(error);
  327. }
  328.  
  329. /****************************************************************************/
  330.  
  331. VOID
  332. CloseSashimiResource(struct SashimiResource * resource)
  333. {
  334.     if(resource != NULL)
  335.     {
  336.         Forbid();
  337.  
  338.         resource->sr_Library.lib_OpenCnt--;
  339.  
  340.         Permit();
  341.     }
  342. }
  343.  
  344. struct SashimiResource *
  345. OpenSashimiResource(VOID)
  346. {
  347.     struct SashimiResource * resource;
  348.  
  349.     Forbid();
  350.  
  351.     resource = OpenResource((STRPTR)SashimiResourceName);
  352.     if(resource != NULL)
  353.     {
  354.         resource->sr_Library.lib_OpenCnt++;
  355.     }
  356.  
  357.     Permit();
  358.  
  359.     return(resource);
  360. }
  361.  
  362. /****************************************************************************/
  363.  
  364. VOID
  365. EmptyBuffer(struct SashimiResource * resource)
  366. {
  367.     Disable();
  368.  
  369.     resource->sr_FIFOReadIndex        = 0;
  370.     resource->sr_FIFOWriteIndex        = 0;
  371.     resource->sr_FIFOBytesStored    = 0;
  372.     resource->sr_FIFOOverrun        = FALSE;
  373.     resource->sr_FIFOWrapped        = FALSE;
  374.  
  375.     Enable();
  376. }
  377.  
  378. LONG
  379. SaveBuffer(const STRPTR name,struct SashimiResource * resource)
  380. {
  381.     STRPTR bufferCopy;
  382.     LONG totalSize;
  383.     LONG error = OK;
  384.  
  385.     totalSize = resource->sr_FIFOTotalSize;
  386.  
  387.     /* We allocate a temporary buffer to store the ring
  388.      * buffer data in.
  389.      */
  390.     bufferCopy = AllocVec(totalSize,MEMF_ANY|MEMF_PUBLIC);
  391.     if(bufferCopy != NULL)
  392.     {
  393.         BOOL wrapped;
  394.         BOOL overrun;
  395.         LONG writeIndex;
  396.         LONG bytesInBuffer;
  397.         BPTR file;
  398.  
  399.         /* Halt multitasking for a tick. */
  400.         Forbid();
  401.  
  402.         wrapped = resource->sr_FIFOWrapped;
  403.         overrun = resource->sr_FIFOOverrun;
  404.  
  405.         /* The index counter indicates how many bytes
  406.          * have been written to the ring buffer, unless
  407.          * the buffer index has wrapped around already.
  408.          */
  409.         writeIndex = bytesInBuffer = resource->sr_FIFOWriteIndex;
  410.  
  411.         /* If the buffer index has wrapped around, then
  412.          * the entire buffer is filled with data.
  413.          */
  414.         if(wrapped)
  415.             bytesInBuffer = totalSize;
  416.  
  417.         /* Make a copy of the current buffer contents. */
  418.         if(bytesInBuffer > 0)
  419.         {
  420.             /* For a wrapped buffer, "unfold" the FIFO. */
  421.             if(writeIndex < bytesInBuffer && wrapped)
  422.             {
  423.                 /* Store the oldest buffer contents first. */
  424.                 CopyMem(resource->sr_FIFO + writeIndex,bufferCopy,bytesInBuffer - writeIndex);
  425.  
  426.                 /* Add the most recent data. */
  427.                 CopyMem(resource->sr_FIFO,bufferCopy + bytesInBuffer - writeIndex,writeIndex);
  428.             }
  429.             else
  430.             {
  431.                 CopyMem(resource->sr_FIFO,bufferCopy,bytesInBuffer);
  432.             }
  433.         }
  434.  
  435.         /* Enable multitasking again. */
  436.         Permit();
  437.  
  438.         /* Write the buffer contents. */
  439.         file = Open((STRPTR)name,MODE_NEWFILE);
  440.         if(file != NULL)
  441.         {
  442.             if(overrun)
  443.             {
  444.                 if(FPrintf(file,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
  445.                     error = IoErr();
  446.             }
  447.  
  448.             if(error == OK && wrapped)
  449.             {
  450.                 if(FPrintf(file,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
  451.                     error = IoErr();
  452.             }
  453.  
  454.             /* FPrintf() is a buffered I/O routine, this is why we need to flush the
  455.              * output buffer here. Otherwise, it would be flushed after the Write()
  456.              * command below is finished and the file is closed. This is not what
  457.              * we want as that would have the effect of adding the messages above
  458.              * to the end of the file.
  459.              */
  460.             if(error == OK)
  461.             {
  462.                 Flush(file);
  463.             }
  464.  
  465.             if(error == OK && bytesInBuffer > 0)
  466.             {
  467.                 if(Write(file,bufferCopy,bytesInBuffer) != bytesInBuffer)
  468.                     error = IoErr();
  469.             }
  470.  
  471.             Close(file);
  472.         }
  473.         else
  474.         {
  475.             error = IoErr();
  476.         }
  477.  
  478.         FreeVec(bufferCopy);
  479.     }
  480.     else
  481.     {
  482.         error = ERROR_NO_FREE_STORE;
  483.     }
  484.  
  485.     return(error);
  486. }
  487.  
  488. /****************************************************************************/
  489.  
  490. int
  491. main(int argc,char **argv)
  492. {
  493.     int result = RETURN_FAIL;
  494.  
  495.     /* Kickstart 2.04 and a Shell window are required. */
  496.     if(DOSBase->lib_Version >= 37 && argc > 0)
  497.     {
  498.         struct RDArgs * rdargs;
  499.  
  500.         rdargs = ReadArgs((STRPTR)ShellTemplate,(LONG *)&ShellArguments,NULL);
  501.         if(rdargs != NULL)
  502.         {
  503.             struct SashimiResource * resource;
  504.             struct MsgPort * timePort = NULL;
  505.             struct timerequest * timeRequest = NULL;
  506.             BOOL added = FALSE;
  507.             BOOL opened = FALSE;
  508.             LONG error = OK;
  509.             BPTR oldOutput = NULL;
  510.             BPTR newOutput = NULL;
  511.             BPTR oldInput = NULL;
  512.             BPTR newInput = NULL;
  513.             struct MsgPort * oldConsoleTask = NULL;
  514.             STRPTR saveFile;
  515.  
  516.             /* Fill in the save file name, we might need it later. */
  517.             if(ShellArguments.SaveAs != NULL)
  518.                 saveFile = ShellArguments.SaveAs;
  519.             else
  520.                 saveFile = "T:sashimi.out";
  521.  
  522.             /* Try to open the resource, and if that fails, create one. */
  523.             resource = OpenSashimiResource();
  524.             if(resource != NULL)
  525.             {
  526.                 opened = TRUE;
  527.             }
  528.             else
  529.             {
  530.                 ULONG bufferSize;
  531.  
  532.                 /* The default buffer size is 32K. */
  533.                 bufferSize = 32 * 1024;
  534.  
  535.                 /* Check for a specific buffer size (power of two). */
  536.                 if(ShellArguments.BufferK != NULL)
  537.                     bufferSize = 1024 * (*ShellArguments.BufferK);
  538.  
  539.                 /* Check for a specific buffer size. */
  540.                 if(ShellArguments.BufferSize != NULL)
  541.                     bufferSize = (ULONG)(*ShellArguments.BufferSize);
  542.  
  543.                 /* Don't make the buffer too small. */
  544.                 if(bufferSize < 4096)
  545.                     bufferSize = 4096;
  546.  
  547.                 /* Add the resource to the public list. Note that
  548.                  * the patches are not installed yet.
  549.                  */
  550.                 error = AddSashimiResource(bufferSize,&resource);
  551.                 if(error == OK)
  552.                 {
  553.                     added = TRUE;
  554.  
  555.                     /* Check if we should periodically check
  556.                      * the ring buffer.
  557.                      */
  558.                     if(ShellArguments.TimerOn)
  559.                     {
  560.                         error = ERROR_NO_FREE_STORE;
  561.  
  562.                         /* Set up the timer.device interface. */
  563.                         timePort = CreateMsgPort();
  564.                         if(timePort != NULL)
  565.                         {
  566.                             timeRequest = (struct timerequest *)CreateIORequest(timePort,sizeof(*timeRequest));
  567.                             if(timeRequest != NULL)
  568.                             {
  569.                                 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
  570.                                     error = OK;
  571.                             }
  572.                         }
  573.                     }
  574.                 }
  575.             }
  576.  
  577.             /* Did we get everything we wanted? */
  578.             if(error != OK)
  579.             {
  580.                 PrintFault(error,"Sashimi");
  581.                 result = RETURN_ERROR;
  582.             }
  583.             else
  584.             {
  585.                 if(opened)
  586.                 {
  587.                     /* Save the current ring buffer contents? */
  588.                     if(ShellArguments.SaveAs != NULL || ShellArguments.Save)
  589.                     {
  590.                         LONG error;
  591.  
  592.                         error = SaveBuffer(saveFile,resource);
  593.                         if(error == OK)
  594.                             Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  595.                         else
  596.                             PrintFault(error,saveFile);
  597.                     }
  598.  
  599.                     /* Empty the ring buffer? */
  600.                     if(ShellArguments.Empty)
  601.                     {
  602.                         EmptyBuffer(resource);
  603.  
  604.                         Printf("Sashimi buffer cleared.\n");
  605.                     }
  606.  
  607.                     /* Turn off Sashimi? */
  608.                     if(ShellArguments.Off)
  609.                     {
  610.                         struct Task * owner;
  611.  
  612.                         Forbid();
  613.  
  614.                         /* We cannot tell Sashimi to quit
  615.                          * if there is a single customer
  616.                          * left, such as us. This is why
  617.                          * we close the resource and
  618.                          * signal Sashimi to quit.
  619.                          */
  620.                         owner = resource->sr_Owner;
  621.                         CloseSashimiResource(resource);
  622.                         resource = NULL;
  623.  
  624.                         Signal(owner,SIGBREAKF_CTRL_C);
  625.  
  626.                         Permit();
  627.                     }
  628.                 }
  629.  
  630.                 if(added)
  631.                 {
  632.                     ULONG signalsReceived,signalsToWaitFor;
  633.                     BOOL done;
  634.  
  635.                     /* Open a console window? */
  636.                     if(ShellArguments.Console)
  637.                     {
  638.                         STRPTR consoleWindow;
  639.                         LONG error = OK;
  640.  
  641.                         if(ShellArguments.Window != NULL)
  642.                             consoleWindow = ShellArguments.Window;
  643.                         else
  644.                             consoleWindow = "CON:0/20/640/100/Sashimi  [Ctrl]+E=Empty  [Ctrl]+F=File  [Ctrl]+D=Reset console/AUTO/CLOSE/WAIT/INACTIVE";
  645.  
  646.                         /* Open the window and make it the default
  647.                          * I/O stream.
  648.                          */
  649.                         newInput = Open(consoleWindow,MODE_NEWFILE);
  650.                         if(newInput != NULL)
  651.                         {
  652.                             oldConsoleTask = SetConsoleTask(((struct FileHandle *)BADDR(newInput))->fh_Type);
  653.                             newOutput = Open("CONSOLE:",MODE_OLDFILE);
  654.                             if(newOutput != NULL)
  655.                             {
  656.                                 oldInput = SelectInput(newInput);
  657.                                 oldOutput = SelectOutput(newOutput);
  658.                             }
  659.                             else
  660.                             {
  661.                                 error = IoErr();
  662.  
  663.                                 /* Return to the original console task. */
  664.                                 SetConsoleTask(oldConsoleTask);
  665.                                 oldConsoleTask = NULL;
  666.                             }
  667.                         }
  668.                         else
  669.                         {
  670.                             error = IoErr();
  671.                         }
  672.  
  673.                         if(error != OK)
  674.                             PrintFault(error,consoleWindow);
  675.                     }
  676.  
  677.                     /* Show the banner message. */
  678.                     if(NOT ShellArguments.NoPrompt && NOT ShellArguments.Quiet)
  679.                     {
  680.                         struct Process * cli = (struct Process *)FindTask(NULL);
  681.                         LONG maxCli,thisCli = 1,i;
  682.  
  683.                         /* Find our current CLI process number. */
  684.                         maxCli = MaxCli();
  685.                         for(i = 1 ; i <= maxCli ; i++)
  686.                         {
  687.                             if(FindCliProc(i) == cli)
  688.                             {
  689.                                 thisCli = i;
  690.                                 break;
  691.                             }
  692.                         }
  693.  
  694.                         Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli);
  695.                     }
  696.  
  697.                     SashimiResource = resource;
  698.                     InstallPatches();
  699.  
  700.                     signalsToWaitFor = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | 
  701.                                        SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F |
  702.                                        resource->sr_OwnerSigMask;
  703.  
  704.                     /* Start the timer. */
  705.                     if(timePort != NULL)
  706.                     {
  707.                         signalsToWaitFor |= (1UL << timePort->mp_SigBit);
  708.  
  709.                         timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  710.                         timeRequest->tr_time.tv_secs    = 0;
  711.                         timeRequest->tr_time.tv_micro    = MILLION / 10;
  712.  
  713.                         SendIO((struct IORequest *)timeRequest);
  714.                     }
  715.  
  716.                     done = FALSE;
  717.                     do
  718.                     {
  719.                         signalsReceived = Wait(signalsToWaitFor);
  720.  
  721.                         /* Check if we should test the buffer. */
  722.                         if(timePort != NULL)
  723.                         {
  724.                             if(signalsReceived & (1UL << timePort->mp_SigBit))
  725.                             {
  726.                                 signalsReceived |= resource->sr_OwnerSigMask;
  727.  
  728.                                 WaitIO((struct IORequest *)timeRequest);
  729.  
  730.                                 /* Restart the timer. */
  731.                                 timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  732.                                 timeRequest->tr_time.tv_secs    = 0;
  733.                                 timeRequest->tr_time.tv_micro    = MILLION / 10;
  734.  
  735.                                 SendIO((struct IORequest *)timeRequest);
  736.                             }
  737.                         }
  738.  
  739.                         /* Check if we should test the buffer. */
  740.                         if(signalsReceived & resource->sr_OwnerSigMask)
  741.                         {
  742.                             if(NOT ShellArguments.Quiet)
  743.                             {
  744.                                 struct SashimiResource * sr = SashimiResource;
  745.                                 UBYTE localBuffer[256];
  746.                                 LONG filled = 0;
  747.  
  748.                                 /* Try to empty the ring buffer. */
  749.                                 while(sr->sr_FIFOBytesStored > 0)
  750.                                 {
  751.                                     /* Read the next byte. */
  752.                                     localBuffer[filled++] = sr->sr_FIFO[sr->sr_FIFOReadIndex];
  753.  
  754.                                     sr->sr_FIFOBytesStored--;
  755.                                     sr->sr_FIFOReadIndex = (sr->sr_FIFOReadIndex + 1) % sr->sr_FIFOTotalSize;
  756.  
  757.                                     /* Has the buffer been filled to the brim? */
  758.                                     if(filled == sizeof(localBuffer))
  759.                                     {
  760.                                         ULONG moreSignals;
  761.  
  762.                                         /* Check if there is a message for us. */
  763.                                         moreSignals = SetSignal(0,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
  764.  
  765.                                         /* Save the ring buffer to a file? */
  766.                                         if(moreSignals & SIGBREAKF_CTRL_F)
  767.                                         {
  768.                                             LONG error;
  769.  
  770.                                             error = SaveBuffer(saveFile,resource);
  771.                                             if(error == OK)
  772.                                                 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  773.                                             else
  774.                                                 PrintFault(error,saveFile);
  775.                                         }
  776.  
  777.                                         /* Empty the ring buffer? */
  778.                                         if(moreSignals & SIGBREAKF_CTRL_E)
  779.                                         {
  780.                                             EmptyBuffer(resource);
  781.  
  782.                                             Printf("Sashimi buffer cleared.\n");
  783.                                         }
  784.  
  785.                                         /* Stop Sashimi? */
  786.                                         if(moreSignals & SIGBREAKF_CTRL_C)
  787.                                         {
  788.                                             signalsReceived |= SIGBREAKF_CTRL_C;
  789.  
  790.                                             filled = 0;
  791.                                             break;
  792.                                         }
  793.  
  794.                                         /* Write the buffer to the file. */
  795.                                         Write(Output(),localBuffer,filled);
  796.                                         filled = 0;
  797.                                     }
  798.                                 }
  799.  
  800.                                 /* Store the remaining buffer contents. */
  801.                                 if(filled > 0)
  802.                                 {
  803.                                     Write(Output(),localBuffer,filled);
  804.                                 }
  805.                             }
  806.                         }
  807.  
  808.                         /* Save current buffer to file. */
  809.                         if(signalsReceived & SIGBREAKF_CTRL_F)
  810.                         {
  811.                             LONG error;
  812.  
  813.                             error = SaveBuffer(saveFile,resource);
  814.                             if(error == OK)
  815.                             {
  816.                                 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  817.                             }
  818.                             else
  819.                             {
  820.                                 PrintFault(error,saveFile);
  821.                             }
  822.                         }
  823.  
  824.                         /* Empty the buffer. */
  825.                         if(signalsReceived & SIGBREAKF_CTRL_E)
  826.                         {
  827.                             EmptyBuffer(resource);
  828.  
  829.                             Printf("Sashimi buffer cleared.\n");
  830.                         }
  831.  
  832.                         /* Reset the terminal. */
  833.                         if(signalsReceived & SIGBREAKF_CTRL_D)
  834.                         {
  835.                             Printf("\033c");
  836.                             Flush(Output());
  837.                         }
  838.  
  839.                         /* Terminate the program. */
  840.                         if(signalsReceived & SIGBREAKF_CTRL_C)
  841.                         {
  842.                             BOOL terminate = FALSE;
  843.  
  844.                             if(ShellArguments.AskExit)
  845.                             {
  846.                                 UBYTE buffer[4];
  847.  
  848.                                 Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
  849.                                 Flush(Output());
  850.  
  851.                                 buffer[0] = '\0';
  852.  
  853.                                 if(FGets(Input(),buffer,sizeof(buffer)-1) != NULL)
  854.                                 {
  855.                                     if(buffer[0] == 'y' || buffer[0] == 'Y')
  856.                                         terminate = TRUE;
  857.                                 }
  858.                             }
  859.                             else
  860.                             {
  861.                                 terminate = TRUE;
  862.                             }
  863.  
  864.                             if(terminate)
  865.                             {
  866.                                 if(RemoveSashimiResource(resource) == OK)
  867.                                 {
  868.                                     Printf("Sashimi removed.\n");
  869.                                     done = TRUE;
  870.                                 }
  871.                             }
  872.                         }
  873.                     }
  874.                     while(NOT done);
  875.  
  876.                     RemovePatches();
  877.  
  878.                     /* Stop the timer. */
  879.                     if(timePort != NULL)
  880.                     {
  881.                         if(CheckIO((struct IORequest *)timeRequest) == BUSY)
  882.                             AbortIO((struct IORequest *)timeRequest);
  883.  
  884.                         WaitIO((struct IORequest *)timeRequest);
  885.                     }
  886.  
  887.                     /* Check if we should and could save the ring buffer. */
  888.                     if(ShellArguments.AskSave && (resource->sr_FIFOWrapped || resource->sr_FIFOWriteIndex > 0))
  889.                     {
  890.                         UBYTE name[256];
  891.  
  892.                         Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
  893.                         Flush(Output());
  894.  
  895.                         name[0] = '\0';
  896.  
  897.                         if(FGets(Input(),name,sizeof(name)-1) != NULL)
  898.                         {
  899.                             LONG error;
  900.                             int i;
  901.  
  902.                             for(i = strlen(name)-1 ; i >= 0 ; i--)
  903.                             {
  904.                                 if(name[i] == '\n')
  905.                                     name[i] = '\0';
  906.                             }
  907.  
  908.                             error = SaveBuffer(name,resource);
  909.                             if(error == OK)
  910.                             {
  911.                                 Printf("Sashimi buffer saved as \"%s\".\n",name);
  912.                             }
  913.                             else
  914.                             {
  915.                                 PrintFault(error,name);
  916.                             }
  917.                         }
  918.                     }
  919.  
  920.                     FreeSashimiResource(resource);
  921.                     resource = NULL;
  922.                 }
  923.  
  924.                 result = RETURN_OK;
  925.             }
  926.  
  927.             /* Close the resource, if we opened it. */
  928.             if(opened)
  929.             {
  930.                 CloseSashimiResource(resource);
  931.             }
  932.  
  933.             /* Remove and free the resource if we added it. */
  934.             if(added)
  935.             {
  936.                 RemoveSashimiResource(resource);
  937.                 FreeSashimiResource(resource);
  938.             }
  939.  
  940.             /* Clean up the timer.device interface. */
  941.             if(timeRequest != NULL)
  942.             {
  943.                 if(timeRequest->tr_node.io_Device != NULL)
  944.                     CloseDevice((struct IORequest *)timeRequest);
  945.  
  946.                 DeleteIORequest((struct IORequest *)timeRequest);
  947.             }
  948.  
  949.             DeleteMsgPort(timePort);
  950.  
  951.             /* Reset and clean up the console I/O streams. */
  952.             if(oldOutput != NULL)
  953.                 SelectOutput(oldOutput);
  954.  
  955.             if(oldInput != NULL)
  956.                 SelectInput(oldInput);
  957.  
  958.             if(newOutput != NULL)
  959.                 Close(newOutput);
  960.  
  961.             if(oldConsoleTask)
  962.                 SetConsoleTask(oldConsoleTask);
  963.  
  964.             if(newInput != NULL)
  965.                 Close(newInput);
  966.  
  967.             FreeArgs(rdargs);
  968.         }
  969.         else
  970.         {
  971.             PrintFault(IoErr(),"Sashimi");
  972.  
  973.             result = RETURN_ERROR;
  974.         }
  975.     }
  976.  
  977.     return(result);
  978. }
  979.